//go:build linux

package transport

import (
	"golang.org/x/sys/unix"
)

var WorkerCount = 40

func (w *transportPool) Init() error {
	epFd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
	w.fd = epFd
	return err
}

func (w *transportPool) Add(t Transport) error {
	w.transports.Store(t.FD(), t)
	event := unix.EpollEvent{
		Fd:     int32(t.FD()),
		Events: unix.EPOLLIN | unix.EPOLLRDHUP,
	}
	return unix.EpollCtl(w.fd, unix.EPOLL_CTL_ADD, int(t.FD()), &event)
}

func (w *transportPool) Remove(t Transport) error {
	w.transports.Delete(t.FD())
	event := unix.EpollEvent{
		Fd:     int32(t.FD()),
		Events: unix.EPOLLIN | unix.EPOLLRDHUP,
	}
	return unix.EpollCtl(w.fd, unix.EPOLL_CTL_DEL, int(t.FD()), &event)
}

func (w *transportPool) waitMessage() ([]Transport, []Transport, error) {
	events := make([]unix.EpollEvent, WorkerCount)
	for {
		n, err := unix.EpollWait(w.fd, events, -1)
		if n == -1 {
			if err == unix.EINTR {
				continue
			}
			return nil, nil, err
		}
		if n == 0 {
			// If there are no events, try again.
			continue
		}
		ts := make([]Transport, 0)
		closed := make([]Transport, 0)
		for _, event := range events[:n] {
			if t, ok := w.getTransport(int(event.Fd)); ok {
				if event.Events&unix.EPOLLIN != 0 {
					ts = append(ts, t)
				}
				if event.Events&(unix.EPOLLERR|unix.EPOLLHUP|unix.EPOLLRDHUP) != 0 {
					w.closeTransport(t)
					closed = append(closed, t)
				}
			} else {
				_ = unix.EpollCtl(w.fd, unix.EPOLL_CTL_DEL, int(event.Fd), &event)
			}
		}
		return ts, closed, nil
	}
}
